package dawnland03.model.entity;

import dawnland03.model.item.ItemType;
import dawnland03.model.entity.attribute.PhysicalAttribute;
import dawnland03.model.entity.attribute.Position;
import dawnland03.model.team.Team;

import java.util.Map;
import java.util.HashMap;

/**
 * User: Petru Obreja (obrejap@yahoo.com)
 * Date: Jan 18, 2010
 * Time: 10:17:00 PM
 */
public class EntityImpl implements Entity {
    private final Integer id;
    private Position position;
    private Map<ItemType, Integer> items; //map of type and quantity
    private Map<PhysicalAttribute, Double> physicalAttributes; //map of physicalAttribute and value
    private Team team;
    private EntityBrain entityBrain;

    EntityImpl(Integer id, Position position, Map<PhysicalAttribute, Double> physicalAttributes, Team team) {
        this.id = id;
        this.position = position;
        items = new HashMap<ItemType, Integer>();
        this.physicalAttributes = physicalAttributes;
        this.team = team;
    }

    public Integer getId() {
        return id;
    }

    public Position getPosition() {
        return position;
    }

    public synchronized Integer peekItemType(ItemType itemType) {
        return items.get(itemType);
    }

    public synchronized Integer putItemType(ItemType itemType, Integer quantity) {
        if (quantity < 0) {
            throw new IllegalStateException("Quantity < 0");
        }
        Integer currentQuantity = items.get(itemType);
        if (currentQuantity != null) {
            items.put(itemType, currentQuantity + quantity);
            return currentQuantity + quantity;
        } else {
            items.put(itemType, quantity);
            return quantity;
        }

    }

    public synchronized Double peekPhysicalAttribute(PhysicalAttribute physicalAttribute) {
        return physicalAttributes.get(physicalAttribute);
    }

    public synchronized Double increasePhysicalAttribute(PhysicalAttribute physicalAttribute, Double gain) {
        Double currentValue = physicalAttributes.get(physicalAttribute);
        //if 'gain' is negative, nothing happens.
        if(gain<=0){
            return currentValue;
        }
        Double increasedValue = currentValue + gain;
        physicalAttributes.put(physicalAttribute, increasedValue);
        return increasedValue;
    }

    public Team getTeam() {
        return team;
    }

    public synchronized EntitySnapshot getEntitySnapshot() {
        Map<PhysicalAttribute, Double> clonedPhysicalAttributes = new HashMap<PhysicalAttribute, Double>(physicalAttributes.size());
        for(Map.Entry<PhysicalAttribute, Double> mapEntry: physicalAttributes.entrySet()){
            clonedPhysicalAttributes.put(mapEntry.getKey(), mapEntry.getValue()); //Double is immutable
        }
        Map<ItemType, Integer> clonedItems = new HashMap<ItemType, Integer>(items.size());
        for(Map.Entry<ItemType, Integer> mapEntry: items.entrySet()){
            clonedItems.put(mapEntry.getKey(), mapEntry.getValue()); //Integer is immutable
        }
        return new EntitySnapshot(id, position.getX(), position.getY(), position.getMatrixCell().getId(),
                clonedPhysicalAttributes, clonedItems);
    }    
    

    EntityBrain getEntityBrain() {
        return entityBrain;
    }

    void setEntityBrain(EntityBrain entityBrain) {
        this.entityBrain = entityBrain;
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EntityImpl entity = (EntityImpl) o;

        if (!id.equals(entity.id)) return false;

        return true;
    }

    public int hashCode() {
        return id.hashCode();
    }

    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("E(").append(id).append(")");
        //items
        if (items.size() > 0) {
            stringBuilder.append("{");
            for (Map.Entry<ItemType, Integer> item : items.entrySet()) {
                stringBuilder.append("[").append(item.getKey()).append("-").append(item.getValue()).append("]");
            }
            stringBuilder.append("}");
        }
        //physicalAttributes
        stringBuilder.append("{");
        for (Map.Entry<PhysicalAttribute, Double> physicalAttribute : physicalAttributes.entrySet()) {
            stringBuilder.append("[").append(physicalAttribute.getKey()).append("-");
            stringBuilder.append(String.format("%.4f",physicalAttribute.getValue())).append("]");
        }
        stringBuilder.append("}");
        return stringBuilder.toString();
    }
}
